#include "module_heater.h"
#include "lwrb.h"
#include "module_pid.h"
static struct heater_total_status heat_group[MODULE_HEAT_NUM];
static lwrb_t local_lwrb;
static uint8_t loacl_buffer[LWRB_BUFFER_SIZE] = {0};
static heat_cb heat_notify_cb;
static heat_cb_data user_private_data;

void heat_notify_cb_func(enum HEATER_EV ev_type, uint8_t ch, void *send_data)
{
    heat_packet_data heat_cb_packet;
    heat_cb_packet.ev_type = ev_type;
    heat_cb_packet.ch = ch;
    memcpy(&heat_cb_packet.data, send_data, sizoef(heat_cb_packet.data));

    if(heat_notify_cb != NULL)
        heat_notify_cb(user_private_data, &heat_cb_packet);
}

void module_heater_init(heat_cb func, heat_cb_data data)
{
    heat_notify_cb = func;
    user_private_data = data;
    heat_port_init();
    lwrb_init(&local_lwrb, loacl_buffer, LWRB_BUFFER_SIZE);
#define TEMP_TYPICAL_VALUE 0
    int16_t temp_voltage = 0;
    int16_t rt_temp = 0;

    for(uint8_t ch = 0; ch < MODULE_HEAT_NUM; ch++)
    {
        switch_heat_port_temp_to_voltage(ch, TEMP_TYPICAL_VALUE, &temp_voltage);
        heat_group[ch].ch = ch;
        heat_group[ch].en_switch = false;
        heat_group[ch].state = HEATER_WORK_STATE_INIT;
        heat_group[ch].user_temp = TEMP_TYPICAL_VALUE;
        heat_group[ch].user_temp_vol = temp_voltage;

        get_heat_port_rt_value(ch, &temp_voltage);
        switch_heat_port_voltage_to_temp(ch, temp_voltage, &rt_temp);
        heat_group[ch].rt_temp = rt_temp;
        heat_group[ch].rt_temp_vol = temp_voltage;

        heat_group[ch].error = get_heater_link_status(heat_group[ch].rt_temp_vol);
        heat_group[ch].tick =heat_port_get_tick() ;

        pid_init(&(heat_group[ch].pid_core), 0, 12, 5000, 200, 500);
    }
}

void module_heater_deinit(void)
{
    lwrb_free(&local_lwrb);
}

void heater_pid_poll(uint8_t ch, int16_t rt_temp_vol)
{
    pid_calc(&heat_group[ch].pid_core, rt_temp_vol);
    heat_port_set_percent(ch, heat_group[ch].pid_core.out);
}

void module_heater_poll(void)
{
    static heat_packet_data recv_packet;

    if(lwrb_read(&local_lwrb, &recv_packet, sizeof(recv_packet)) != 0)
    {
        uint8_t ch = recv_packet.ch;

        switch (recv_packet.ev_type)
        {
            case HEATER_EV_NULL:
                heat_group[ch].ev_flag |= HEATER_EV_NULL;
                break;

            case HEATER_EV_STATE:
                heat_group[ch].ev_flag |= HEATER_EV_STATE;
                heat_group[ch].state = recv_packet.data.state;
                break;

            case HEATER_EV_ERROR         :
                heat_group[ch].ev_flag |= HEATER_EV_ERROR;
                heat_group[ch].error = recv_packet.data.error;

                if(heat_group[ch].error != HEATER_WORK_ERROR_OK)
                {
                    heat_group[ch].en_switch = false;
                }

                break;

            case HEATER_EV_HEATER_SW     :
                heat_group[ch].ev_flag |= HEATER_EV_HEATER_SW;
                heat_group[ch].en_switch = recv_packet.data.en_switch;
                break;

            case HEATER_EV_USER_TEMP     :
                heat_group[ch].ev_flag |= HEATER_EV_USER_TEMP;
                heat_group[ch].user_temp = recv_packet.data.temp;
                switch_heat_port_temp_to_voltage(ch, heat_group[ch].user_temp, &heat_group[ch].user_temp_vol);
                pid_set_target(&(heat_group[ch].pid_core), heat_group[ch].user_temp_vol);
                break;

            case HEATER_EV_RT_TEMP       :
                heat_group[ch].ev_flag |= HEATER_EV_RT_TEMP;
                heat_group[ch].rt_temp = recv_packet.data.temp;
                switch_heat_port_temp_to_voltage(ch, heat_group[ch].rt_temp, &heat_group[ch].rt_temp_vol);
                break;

            case HEATER_EV_TOTAL_STATUS  :
                heat_group[ch].ev_flag |= HEATER_EV_TOTAL_STATUS;
                break;

            default:
                break;
        }
    }

    for(uint8_t ch = 0; ch < MODULE_HEAT_NUM; ch++)
    {
        {
            int16_t rt_adc_voltage_mv = 0;
            int16_t rt_temp = 0;
            uint8_t rt_link_status = 0;
            get_heat_port_rt_value_mv(ch, &rt_adc_voltage_mv);
            switch_heat_port_voltage_to_temp(ch, rt_adc_voltage_mv, &rt_temp);
            heat_group[ch].rt_temp_vol = rt_adc_voltage_mv;
            heat_group[ch].rt_temp = rt_temp;
            rt_link_status = get_heater_link_status(heat_group[ch].rt_temp_vol);

            if(rt_link_status != heat_group[ch].error)
            {
                heat_group[ch].error = rt_link_status;
                heat_notify_cb_func(HEATER_EV_ERROR, ch, rt_link_status);
            }
        }

        switch (heat_group[ch].state)
        {
            case HEATER_WORK_STATE_INIT:
                if(heat_group[ch].ev_flag & HEATER_EV_HEATER_SW)
                {
                    if((heat_group[ch].en_switch == true) && (heat_group[ch].error == HEATER_WORK_ERROR_OK))
                    {
                        heat_group[ch].tick = heat_port_get_tick();
                        heat_port_set_switch(ch, true);
                        heat_group[ch].state = HEATER_WORK_STATE_RUNNING;
                        heat_notify_cb_func(HEATER_EV_HEATER_SW, ch, heat_group[ch].en_switch);
                    }
                }

                break;

            case HEATER_WORK_STATE_RUNNING:
                heater_pid_poll(ch,  heat_group[ch].rt_temp_vol);
                uint32_t rt_tick = heat_port_get_tick();

                if((rt_tick - heat_group[ch].tick) > HEAT_TIME_TICK_MAX)
                {
                    heat_group[ch].en_switch = false;
                    heat_port_set_switch(ch, false);
                    heat_notify_cb_func(HEATER_EV_ERROR, ch, heat_group[ch].error);
                }

                if(heat_group[ch].ev_flag & HEATER_EV_HEATER_SW)
                {
                    if(heat_group[ch].en_switch == false)
                    {
                        heat_port_set_switch(ch, false);
                        heat_group[ch].state = HEATER_WORK_STATE_INIT;
                        heat_notify_cb_func(HEATER_EV_HEATER_SW, ch, heat_group[ch].en_switch);
                    }
                }

                if(heat_group[ch].ev_flag & HEATER_EV_ERROR)
                {
                    if(heat_group[ch].error != HEATER_WORK_ERROR_OK)
                    {
                        heat_group[ch].en_switch = false;
                        heat_port_set_switch(ch, false);
                        heat_group[ch].state = HEATER_WORK_STATE_INIT;
                        heat_notify_cb_func(HEATER_EV_ERROR, ch, heat_group[ch].en_switch);
                    }
                }

                if(abs(heat_group[ch].rt_temp_vol - heat_group[ch].user_temp_vol) < TEMP_STEP_VOL_MV)
                {
                    heat_group[ch].state = HEATER_WORK_STATE_ARRIVE;
                    heat_notify_cb_func(HEATER_EV_STATE, ch, heat_group[ch].state);
                }

                break;

            case HEATER_WORK_STATE_ARRIVE:
                if(abs(heat_group[ch].rt_temp_vol - heat_group[ch].user_temp_vol) > TEMP_STEP_VOL_MV)
                {
                    heat_group[ch].en_switch = true;
                    heat_port_set_switch(ch, true);
                    heat_group[ch].state = HEATER_WORK_STATE_RUNNING;
                    heat_notify_cb_func(HEATER_EV_STATE, ch, heat_group[ch].state);
                }

                if(heat_group[ch].ev_flag & HEATER_EV_HEATER_SW)
                {
                    if(heat_group[ch].en_switch == false)
                    {
                        heat_port_set_switch(ch, false);
                        heat_group[ch].state = HEATER_WORK_STATE_INIT;
                        heat_notify_cb_func(HEATER_EV_HEATER_SW, ch, heat_group[ch].en_switch);
                    }
                }

                if(heat_group[ch].ev_flag & HEATER_EV_ERROR)
                {
                    if(heat_group[ch].error == HEATER_WORK_ERROR_INVALID_NTC)
                    {
                        heat_group[ch].en_switch = false;
                        heat_port_set_switch(ch, false);
                        heat_group[ch].state = HEATER_WORK_STATE_INIT;
                        heat_notify_cb_func(HEATER_EV_ERROR, ch, heat_group[ch].en_switch);
                    }
                }

                if(abs(heat_group[ch].rt_temp_vol - heat_group[ch].user_temp_vol) > HEAT_TIME_TICK_MAX)
                {
                    heat_group[ch].en_switch = false;
                    heat_port_set_switch(ch, false);
                    heat_group[ch].state = HEATER_WORK_STATE_INIT;
                    heat_notify_cb_func(HEATER_EV_ERROR, ch, heat_group[ch].en_switch);
                }

                break;

            default:
                break;
        }
    }
}

void module_heater_set_en(uint8_t ch, bool en)
{
    heat_packet_data send_packet;
    send_packet.ch = ch;
    send_packet.ev_type = HEATER_EV_HEATER_SW;
    send_packet.data.en_switch = en;
    lwrb_write(&local_lwrb, &send_packet, sizeof(send_packet));
}
void module_heater_set_temp(uint8_t ch, int16_t temp)
{
    heat_packet_data send_packet;
    send_packet.ch = ch;
    send_packet.ev_type = HEATER_EV_USER_TEMP;
    send_packet.data.temp = temp;
    lwrb_write(&local_lwrb, &send_packet, sizeof(send_packet));
}

void module_heater_complex(uint8_t ch, bool en, int16_t temp)
{
    module_heater_set_en(ch, en);
    module_heater_set_temp(ch, temp);
}

void module_heater_total_set_en(bool en)
{
    for(uint8_t ch = 0; ch < MODULE_HEAT_NUM; ch++)
    {
        module_heater_set_en(ch, en);
    }
}

void module_heater_set_temp(uint8_t ch, int16_t temp)
{
    for(uint8_t ch = 0; ch < MODULE_HEAT_NUM; ch++)
    {
        module_heater_set_temp(ch, temp);
    }
}

void module_heater_complex(uint8_t ch, bool en, int16_t temp)
{
    for(uint8_t ch = 0; ch < MODULE_HEAT_NUM; ch++)
    {
        module_heater_complex(ch, en, temp);
    }
}

int8_t module_heater_get_max_ch(void)
{
    return MODULE_HEAT_NUM;
}

bool module_heater_get_en(uint8_t ch)
{
    return heat_group[ch].en_switch;
}

int16_t module_heater_get_user_temp(uint8_t ch)
{
    return heat_group[ch].user_temp;
}

int16_t module_heater_get_rt_temp(uint8_t ch)
{
    return heat_group[ch].rt_temp;
}

enum HEATER_WORK_ERROR module_heater_get_error_status(uint8_t ch)
{
    return heat_group[ch].error;
}

void module_heater_get_status(uint8_t ch, struct heater_total_status *info)
{
    memcpy(info, &heat_group[ch], sizeof(heat_group[ch]));
}
